Next.js 入門:使用 next export 輸出 static file


Posted by SimonAllen on 2021-07-15

此篇以 Next.js 11.0.1 版為主,內容僅供參考。

若要使用 Next.js SSG 額外輸出 static HTML,不打算把 SSG 的內容置於 Next.js 的 Node.js Server 上的話,光靠目前 package.json 的 scripts 指令是不夠的,我們需要使用 next export

修改 package.json scripts

使用 create-next-app 建立好預設 Next 專案後,到 package.json 修改 scripts,在 "build":next build 指令後方加上 && next export

  "scripts": {
    "dev": "next dev",
    "build": "next build && next export",
    "start": "next start",
    "lint": "next lint"
  },

原本指令會執行 next build 建構 prod 模式的 next application,現在另外加上&& next export 告訴 Next.js 專案把原本會產進 .next 的檔案也另外執行 next export 輸出來。

趕緊到 terminal 試試看,cd 進入 Next.js 專案後輸入

npm run build

來跑跑看結果。

Error: Image Optimization using Next.js’ default loader is not compatible with next export.

若 Next.js 開發環境和筆者一樣是 11.0.1 版,沒意外建好專案後 next build && next export 會看到此錯誤。

注: 此錯誤未來 Next.js 會(已)修正,在筆者撰寫的當下已有討論 Static Loader for next/image 與 PR Merged Rename next/image dangerously-unoptimized to custom and warn when applicable #26998,目前在 canary 版已修正但這裡還是先以當前正式版本為主。

Error: Image Optimization using Next.js' default loader is not compatible with `next export`.
  Possible solutions:
    - Use `next start` to run a server, which includes the Image Optimization API.
    - Use any provider which supports Image Optimization (like Vercel).
    - Configure a third-party loader in `next.config.js`.
    - Use the `loader` prop for `next/image`.

自從 Next.js 推出自己優化的 Image 元件後,使用 create-next-app 建立預設專案內會包含使用 Image 元件的程式碼,例如我們可以在預設的 /pages/index.js 找到:

import Image from "next/image";
//..略

<Image src="/vercel.svg" alt="Vercel Logo" width={72} height={16} />

預設 my-app 專案後下 next build && next export 會跳這錯誤,是因為 next Image 元件仰賴 Next Server 或第三方圖片處理的服務,此時我們在 local SSG 輸出自然會出問題。

好 OK,靜態頁面 SSG 不用 Image 元件沒關係吧,我們可以試著把 Image 元件改回原本的 HTML <img>試試看吧,殊不知 Next 的 ESLint 馬上逼逼叫:

Do not use <img>. Use Image from 'next/image' instead.

...恩好喔

暫時解法有幾種,其中一種一樣使用 Next 的 Image 元件,然後在 next.config.js 多加上 images 的設定:

module.exports = {
  images: {
    loader: "imgix",
    path: "/",
  },
  // 略...
};

重新執行另加上 && next exportnpm run build,這時應該就會成功了,此時可以看見多了一個 out 資料夾。

out 資料夾

out 資料夾存放著我們 SSG 輸出檔案,預設 HTML 有 index.html404.html 以及其他存放在 _next 資料夾內的 .css.js 檔案。

既然是輸出完的 static file,試著把 out 內的 index.html 直接拖曳進瀏覽器看看。

恩?是有看到 Welcome to Next.js! 等文字,和原本預設 npm run dev 跑的網頁比起來差異是..樣式?

看起來就像是沒載入 css 樣式檔案?

檢查檔案路徑是否有跑掉

輸出的out 資料夾_next 內本來就有.css.js 檔案,既然瀏覽器呈現index.html 樣式沒呈現,我們打開 Chrome 開發者工具來找看看問題在哪:

選擇 Network 後再 reload 一次,發現 .css.js 檔案都 failed,沒有成功載入。

接著回到編輯器如 vscode 打開 out 資料夾內的 index.html,會發現 code 是行數壓縮過單行的樣子,我們可以利用 vscode 文件格式化功能把這份 html 重新排版。

瀏覽排版後 index.html,發現似乎哪裡怪怪的。

hrefsrc 那邊引入 .css.js 的路徑怪怪的,要在 index.html 讀到對應 .css.js ,相對路徑應該是 ./_next/.. 路徑開頭而不是 /_next/.. 開頭

手動作法(不推薦)

這裡先試試手動把每個引入 .css.js 的路徑多加 . 看看。

原本的/_next/ 開頭路徑改成 ./_next/,存檔後再把index.html 直接拖曳進瀏覽器看看。

yes,看起來正常多了。

另外提醒這邊只是為了 debug 測試,實務上不可能每次都自己親手補上這個多出來的 .。前幾篇的文章有提到,我們不太可能也不建議手動修改如 .next 之類的資料夾,理由是由指令產生出來的檔案或資料夾,下次重下指令又會重新產生和覆蓋。

同樣的道理,out 資料夾也是由指令產生出來的,現在修改 out 資料夾內檔案,下次重新 next export 又會把舊的檔案蓋掉,這樣就沒意義了。

修改 next.config.js

這個問題其實社群也有人討論過,按照 Next.js Issues 這篇討論:Generated static files html files have wrong assets paths,我們可以修改 next.config.js,多加上一行 assetPrefix: ".",

module.exports = {
  assetPrefix: ".",
  images: {
    loader: "imgix",
    path: "/",
  },
  // 略...
};

存檔後重下指令 npm run buildexport 看看,試著把 out 內的 index.html 直接拖曳進瀏覽器看看。

這麼一來就正常了。

總結

這篇筆記算是隨手紀錄,不過還是抱怨一下 Next 9 版就推出 SSG,結果現在 11 版用 create-next-app 建立預設專案 next export 還是會報錯。所幸官方社群有討論也有 PR,未來開發者不一定會遇到相同問題。

之後若有 Next.js 筆記,就不會只著墨在 SSG 的功能上,應該會回歸 SSR 那邊相關功能的紀錄。

參考

Nextjs 官方文件: Static HTML Export
Custom loaders are not recognized by next export #21079
add Absolute Imports and Module path aliases #26797
Generated static files html files have wrong assets paths


#Next.js #ssg









Related Posts

PWNLAB: INIT Walkthrough

PWNLAB: INIT Walkthrough

圖論(Graph Theory)

圖論(Graph Theory)

C++筆記 島嶼計算

C++筆記 島嶼計算


Comments